package com.allin.mall.gateway.filter;

import cn.hutool.core.collection.CollectionUtil;
import com.allin.mall.common.core.api.ResultCodeEnum;
import com.allin.mall.common.core.exception.BusinessException;
import com.allin.mall.gateway.properties.SignProperties;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Optional;

@Component
@ConditionalOnProperty(value = "mall.request.sign.enable", havingValue = "true")
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SignFilter implements GlobalFilter {

    /**
     * 请求头里的时间戳
     */
    private static final String HEADER_TIMESTAMP = "t";

    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    @Resource
    private SignProperties properties;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1. 是否在白名单内
        if (isInWhitelist(exchange.getRequest().getURI().getPath())) {
            return chain.filter(exchange);
        }
        // 2. 进行签名校验
        final long timestamp = Optional.ofNullable(exchange.getRequest().getHeaders().get(HEADER_TIMESTAMP)).map(l -> l.get(0)).map(Long::valueOf).orElseThrow(() ->
             new BusinessException(ResultCodeEnum.SYSTEM_ERROR)
        );
        if (Math.abs(System.currentTimeMillis() - timestamp) > 2000) {
            throw new BusinessException(ResultCodeEnum.SYSTEM_ERROR);
        }
        return chain.filter(exchange);
    }

    private boolean isInWhitelist(String path) {
        if (CollectionUtil.isEmpty(properties.getWhiteList())) {
            return false;
        }
        for (String pattern : properties.getWhiteList()) {
            if (pathMatcher.match(pattern, path)) {
                return true;
            }
        }
        return false;
    }
}
